home *** CD-ROM | disk | FTP | other *** search
/ Technotools / Technotools (Chestnut CD-ROM)(1993).ISO / os2tools / ls / ls.c next >
Encoding:
C/C++ Source or Header  |  1991-04-21  |  19.5 KB  |  825 lines

  1. /*
  2.  * File: ls.c
  3.  *
  4.  * Unix-like directory listing program for OS/2
  5.  *
  6.  * Bob Eager   April 1991
  7.  *
  8.  */
  9.  
  10. /*
  11.  * History:
  12.  *    1.0    - Initial version
  13.  *    1.1    - Corrected filename sort for HPFS volumes.
  14.  *    1.2    - Replaced 'isatty' call with local version since MSC one
  15.  *          is broken in version 6.0 (won't differentiate devices).
  16.  *
  17.  */
  18.  
  19. /* Program version information */
  20.  
  21. #define    VERSION        1
  22. #define    EDIT        1
  23.  
  24. #include <sys\types.h>
  25. #include <conio.h>
  26. #include <ctype.h>
  27. #include <direct.h>
  28. #include <errno.h>
  29. #include <search.h>
  30. #include <sys\stat.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <time.h>
  35.  
  36. #define    INCL_DOSDATETIME
  37. #define    INCL_DOSFILEMGR
  38. #include <os2.h>
  39.  
  40. #define    FSQBUFSIZE    100        /* Size of FS query buffer           */
  41. #define    MAXFILE        500        /* Max files per directory           */
  42. #define    SCRSIZ        22        /* Scrolling size of display screen  */
  43. #define    SCRWID        75        /* Column width of display screen    */
  44.  
  45. /* Type definitions */
  46.  
  47. enum    fs_t    {
  48. FS_FAT,                    /* DOS-type (FAT) file system        */
  49. FS_HPFS                    /* High Performance file system      */
  50. };
  51. enum    tm_t    {
  52. TIME_MOD,                /* Sort on time modified             */
  53. TIME_ACC,                /* Sort on time accessed             */
  54. TIME_CRE                /* Sort on time created              */
  55. };
  56.  
  57. /* Format of output buffer -- array of file structs */
  58.  
  59. static struct outbuf {
  60. USHORT    oattr;                /* Attributes            */
  61. FDATE    odate;                /* File date            */
  62. FTIME    otime;                /* File time            */
  63. ULONG    osize;                /* File size (logical)        */
  64. ULONG    oasize;                /* File size (allocated)    */
  65. ULONG    easize;                /* Size of extended attributes    */
  66. CHAR    *oname;                /* File name            */
  67. } *obuf;
  68.  
  69. /* Forward references */
  70.  
  71. static    int    comp(struct outbuf *, struct outbuf *);
  72. static    void    curdrv(CHAR *);
  73. static    CHAR    endlin(void);
  74. static    void    fill(int, struct llst *);
  75. static    enum fs_t fstype(CHAR *);
  76. static    int    gcdate(void);
  77. static    ULONG    getleft(CHAR *, int *);
  78. static    void    longlist(int);
  79. static    char    *mname(int);
  80. static    BOOL    my_isatty(int);
  81. static    void    putusage(void);
  82. static    void    search(CHAR *);
  83. static    void    shortlist(int);
  84.  
  85. /* Help text */
  86.  
  87. static    const    char *helpinfo[] = {
  88. "%s: list contents of directory\n",
  89. "Synopsis: %s [options] file ...",
  90. " Options:",
  91. "    -a  list all files, including hidden and directory",
  92. "    -c  sort by date and time created instead of by name (HPFS only)",
  93. "    -d  output details of directory rather than its contents",
  94. "    -e  output size of extended attributes rather than of file",
  95. "    -h  display this help",
  96. "    -i  display file system type",
  97. "    -l  long listing (attributes, sizes, dates etc.)",
  98. "    -r  reverse direction of sort",
  99. "    -s  output allocated size of each file",
  100. "    -t  sort by date and time modified instead of by name",
  101. "    -u  sort by date and time last accessed instead of by name (HPFS only)",
  102. "    -R  recursively list subdirectories",
  103. "    -1  single column output",
  104. ""
  105. };
  106.  
  107. /* Format of long listing buffer */
  108.  
  109. struct llst {                /* Structure to hold file information*/
  110. CHAR    fattr[7];            /* File attribute string             */
  111. ULONG    size;                /* File size                         */
  112. int    day;                /* The day of creation               */
  113. int    mnum;                /* Month number                      */
  114. int    yr;                /* Year                              */
  115. int    hh;                /* Creation times                    */
  116. int    mm;
  117. int    ap;                /* am or pm                          */
  118. };
  119.  
  120. /* Global variables and flags */
  121.  
  122. static    BOOL    all = 0;        /* -a: Include hidden & system files */
  123. static    BOOL    ll = 0;            /* -l: Long listing                  */
  124. static    BOOL    col1 = 0;        /* -1: 1-column format               */
  125. static    BOOL    direct = 0;        /* -d: Output directory details      */
  126. static    BOOL    eas = 0;        /* -e: Output size of EAs            */
  127. static    BOOL    fsinfo = 0;        /* -i: Output file system info       */
  128. static    BOOL    recd = 0;        /* -R: Recursive descent requested   */
  129. static    BOOL    rev = 0;        /* -r: Reverse sort                  */
  130. static    BOOL    tsrt = 0;        /* -t: Sort the listing by time      */
  131. static    BOOL    usage = 0;        /* -u: Output disk usage             */
  132.  
  133. static    enum tm_t timetype = TIME_MOD;    /* Type of time for sort             */
  134. static    enum fs_t fs;            /* File system type                  */
  135. static    int    np = 0;            /* Number of groups printed          */
  136. static    int    nargs;            /* Number of non-option arguments    */
  137. static    int    drive;            /* Code number for drive requested   */
  138. static    CHAR    *progname;        /* Program name                      */
  139. static    BOOL    tsc;            /* TRUE iff output is to console     */
  140. static    ULONG    total;            /* Total of sizes encountered        */
  141. static    int    lc = 0;            /* Line counter                      */
  142. static    CHAR    spath[_MAX_PATH+2];    /* Holds current drv/pathname string */
  143.  
  144.  
  145. /*
  146.  * Main entry point
  147.  *
  148.  */
  149.  
  150. void main(int argc, CHAR *argv[])
  151. {    CHAR *s;
  152.  
  153.     progname = argv[0];
  154.  
  155.     /* Process input options */
  156.  
  157.     while(--argc > 0 && (*++argv)[0] == '-') {
  158.         for(s = argv[0]+1; *s != '\0'; s++) {
  159.             switch(*s) {
  160.                 case 'a':    /* -a: list all files */
  161.                     all++;
  162.                     break;
  163.  
  164.                 case 'c':    /* -c: creation time sort */
  165.                     tsrt++;
  166.                     timetype = TIME_CRE;
  167.                     break;
  168.  
  169.                 case 'd':    /* -d: directory details */
  170.                     direct++;
  171.                     break;
  172.  
  173.                 case 'e':    /* -e: EA sizes */
  174.                     eas++;
  175.                     break;
  176.  
  177.                 case 'h':    /* -h: print help */
  178.                     putusage();
  179.                     exit(EXIT_SUCCESS);
  180.  
  181.                 case 'i':    /* -i: file system info */
  182.                     fsinfo++;
  183.                     break;
  184.  
  185.                 case 'l':    /* -l: long listing */
  186.                     ll++;
  187.                     break;
  188.  
  189.                 case 'r':    /* -r: reverse sort direction */
  190.                     rev++;
  191.                     break;
  192.  
  193.                 case 's':    /* -s: disk usage */
  194.                     usage++;
  195.                     break;
  196.  
  197.                 case 't':    /* -t: modification time sort */
  198.                     tsrt++;
  199.                     timetype = TIME_MOD;
  200.                     break;
  201.  
  202.                 case 'u':    /* -u: access time sort */
  203.                     tsrt++;
  204.                     timetype = TIME_ACC;
  205.                     break;
  206.  
  207.                 case 'R':    /* -R: recursive list */
  208.                     recd++;
  209.                     break;
  210.  
  211.                 case '1':    /* -1: 1-column listing */
  212.                     col1++;
  213.                     break;
  214.  
  215.                 default:
  216.                     fprintf(stderr,
  217.                     "%s: invalid flag -%c\n", progname, *s);
  218.                     exit(EXIT_FAILURE);
  219.             }
  220.         }
  221.     }
  222.  
  223.     if(direct) usage = recd = 0;
  224.  
  225.     nargs = argc;
  226.     tsc = my_isatty(fileno(stdout));
  227.                     /* See if output to screen */
  228.  
  229.     obuf = (struct outbuf *) malloc(sizeof(*obuf)*MAXFILE);
  230.     if(obuf == (struct outbuf *) NULL) {
  231.         fprintf(stderr, "%s: not enough memory\n", progname);
  232.         exit(EXIT_FAILURE);
  233.     }
  234.  
  235.     if(argc == 0) {            /* Default to current drive */
  236.         argc++;
  237.         curdrv(spath);
  238.     } else (void) strcpy(spath, *argv);
  239.  
  240.     /* Cycle through args present */
  241.  
  242.     for(;;) {
  243.         if(spath[1] == ':' && spath[2] == '\0') {
  244.                     /* If drive only */
  245.             (void) _getdcwd(spath[0]-'a'+1, spath, _MAX_PATH);
  246.         }
  247.  
  248.         fs = fstype(spath);    /* See if FAT or HPFS file system */
  249.  
  250.         search(spath);        /* Do the actual listing */
  251.  
  252.         if(--argc != 0) {
  253.             (void) strcpy(spath, *++argv);
  254.         } else {
  255.             if(usage) {
  256.                 ULONG left = getleft(spath, &drive);
  257.  
  258.                 if(np > 1) {
  259.                     fprintf(stdout,
  260.                         "---------\n%9ld bytes total; ",
  261.                         total);
  262.                 }
  263.                 fprintf(stdout,
  264.                 "%9ld bytes left on drive %c:\n", left,
  265.                     drive + 'a' - 1);
  266.             }
  267.             break;
  268.         }
  269.     }
  270.     free(obuf);
  271.  
  272.     exit(EXIT_SUCCESS);
  273. }
  274.  
  275.  
  276. /*
  277.  * Search 'path' for filename or directory
  278.  *
  279.  */
  280.  
  281. static void search(CHAR *path)
  282. {    USHORT mask = FILE_DIRECTORY;    /* Attribute mask                    */
  283.     char *work;            /* Working path string               */
  284.     int path_len;            /* Length of initial path            */
  285.     USHORT res;            /* Return code from find calls       */
  286.     HDIR hd;            /* Directory handle                  */
  287.     FILEFINDBUF2 *fb;        /* Buffer for file information       */
  288.     USHORT count;            /* Count of files found              */
  289.     int k = 0;            /* Counts number of entries found    */
  290.     CHAR ch;            /* Temporary                         */
  291.     CHAR *name;            /* Temporary                         */
  292.     ULONG bytes = 0;        /* Count of disk usage this directory*/
  293.     enum tm_t tt = timetype;    /* Type of time output/sort          */
  294.     int nargs;            /* Number of files or directories    */
  295.  
  296.     work = (char *) malloc(CCHMAXPATH);
  297.     fb = (FILEFINDBUF2 *) malloc(sizeof(FILEFINDBUF2));
  298.  
  299.     if(fs == FS_FAT) tt = TIME_MOD;    /* Does not keep other times */
  300.  
  301.     if(all) mask = FILE_DIRECTORY | FILE_SYSTEM |
  302.                FILE_HIDDEN | FILE_READONLY | FILE_NORMAL;
  303.  
  304.     (void) strcpy(work, path);
  305.     path_len = strlen(work);    /* Save original path length */
  306.     hd = HDIR_CREATE;        /* Create new directory handle */
  307.     count = 1;            /* Get information about one file */
  308.  
  309.     if(fs == FS_FAT) (void) strlwr(work);
  310.  
  311.     /* Handle the case where the argument refers to a directory, either
  312.        explicitly (it ends in the path separator) or implicitly (it turns
  313.        out to be a directory). Concatenate a full wildcard specification
  314.        to get everything in the directory, unless the '-d' flag was
  315.        specified. */
  316.  
  317.     if(!direct) {
  318.         res = DosFindFirst2(work, &hd, FILE_NORMAL, fb,
  319.             sizeof(FILEFINDBUF2), &count,
  320.             FIL_QUERYEASIZE, (ULONG) 0);
  321.         if(res != 0) count = 0;
  322.  
  323.         if(count == 0 || work[path_len-1] == '\\') {
  324.             if(work[path_len-1] != '\\') {
  325.                 (void) strcat(work, "\\");
  326.                     /* If path is to a directory */
  327.                 path_len++;
  328.             }
  329.             (void) strcat(work, "*.*");
  330.                     /* List everything in it */
  331.         }
  332.         (void) DosFindClose(hd);
  333.     }
  334.  
  335.     /* Main loop to scan all normal files in the directory, and store
  336.        details of them. */
  337.  
  338.     hd = HDIR_CREATE;        /* Create new directory handle */
  339.     count = 1;            /* Get information about one file */
  340.     res = DosFindFirst2(work, &hd, mask, fb, sizeof(FILEFINDBUF2),
  341.         &count, FIL_QUERYEASIZE, (ULONG) 0);
  342.     if(res != 0) count = 0;
  343.  
  344.     if(count != 0) {
  345.         do {
  346.             /* Ignore "." and ".." unless -a option */
  347.  
  348.             if(!(fb->achName[0] == '.' && !all)) {
  349.  
  350.                 /* Store this entry */
  351.  
  352.                 obuf[k].oattr  = fb->attrFile;
  353.                 obuf[k].osize  = fb->cbFile;
  354.                 obuf[k].oasize = fb->cbFileAlloc;
  355.                 if(fb->cbList == sizeof(ULONG))
  356.                     fb->cbList = 0;    /* No real EAs */
  357.                 obuf[k].easize = fb->cbList;
  358.  
  359.                 switch(tt) {
  360.                     case TIME_MOD:
  361.                         obuf[k].otime  = fb->ftimeLastWrite;
  362.                         obuf[k].odate  = fb->fdateLastWrite;
  363.                         break;
  364.  
  365.                     case TIME_ACC:
  366.                         obuf[k].otime  = fb->ftimeLastAccess;
  367.                         obuf[k].odate  = fb->fdateLastAccess;
  368.                         break;
  369.  
  370.                     case TIME_CRE:
  371.                         obuf[k].otime  = fb->ftimeCreation;
  372.                         obuf[k].odate  = fb->fdateCreation;
  373.                 }
  374.  
  375.                 name = (CHAR *) malloc(sizeof(fb->achName)+2);
  376.                         /* Extra byte for possible \ */
  377.                 (void) strcpy(name, fb->achName);
  378.                 obuf[k].oname = name;
  379.  
  380.                 if(usage) {
  381.                     ULONG add = fb->cbFileAlloc;
  382.  
  383.                     if((fb->attrFile & FILE_DIRECTORY) &&
  384.                         fb->achName[0] != '.') {
  385.                         bytes += add;
  386.                     } else {    /* Sum up disk usage */
  387.                         bytes += add;
  388.                     }
  389.                 }
  390.                 if(++k >= MAXFILE) {
  391.                     fprintf(stderr,
  392.                         "%s: more than %d files in directory\n",
  393.                         progname, MAXFILE);
  394.                 }
  395.             }
  396.             count = 1;
  397.             if(DosFindNext(hd, (FILEFINDBUF *) fb,
  398.                 sizeof(FILEFINDBUF2), &count) != 0) count = 0;
  399.         } while(count != 0);
  400.         (void) DosFindClose(hd);
  401.     } else {
  402.         work[path_len-1] = '\0';
  403.         fprintf(stderr,
  404.             "%s: can't find a file or directory named \"%s\"\n",
  405.             progname, work);
  406.         (void) DosFindClose(hd);
  407.         free(work);
  408.     }
  409.  
  410.     work[path_len] = '\0';        /* Restore directory pathname */
  411.  
  412.     ch = endlin();
  413.     if(np++) putchar(ch);        /* Separate listing blocks */
  414.  
  415.     if(usage) {
  416.         total += bytes;        /* Total bytes to date */
  417.         fprintf(stdout, "%9ld ", bytes);
  418.     }
  419.  
  420.     /* Identify the block */
  421.  
  422.     fprintf(stdout, "%s", work);
  423.     if(fsinfo)
  424.         fprintf(stdout, "  (%s)", fs == FS_FAT ? "FAT" : "HPFS");
  425.     ch = endlin();
  426.     fputc(ch, stdout);
  427.  
  428.     /* Sort the entries and print them */
  429.  
  430.     qsort(obuf, k, sizeof(obuf[0]), comp);
  431.     if(ll) longlist(k); else shortlist(k);
  432.  
  433.     /* Free the space allocated for file names */
  434.  
  435.     while(--k >= 0) free(obuf[k].oname);
  436.  
  437.     if(!recd) {            /* Quit if not -R */
  438.         free(work);
  439.         return;
  440.     }
  441.  
  442.     (void) strcat(work, "*.*");
  443.     hd = HDIR_CREATE;        /* Create new directory handle */
  444.     count = 1;
  445.     res = DosFindFirst2(work, &hd, mask, fb, sizeof(FILEFINDBUF2), &count,
  446.         FIL_QUERYEASIZE, (ULONG) 0);
  447.  
  448.     if(count != 0) {        /* Else find all sub-dirs */
  449.         do {
  450.             if(fb->attrFile & FILE_DIRECTORY &&
  451.                fb->achName[0] != '.') {
  452.                 work[path_len] = 0;
  453.                     /* Discard old name */
  454.                 if(fs == FS_FAT)
  455.                     (void) strlwr(fb->achName);
  456.                 (void) strcat(work, fb->achName);
  457.                     /* Install a new one */
  458.                 (void) strcat(work, "\\");
  459.                 search(work);
  460.                     /* And recurse */
  461.             }
  462.             count = 1;
  463.             if(DosFindNext(hd, (FILEFINDBUF *) fb,
  464.                 sizeof(FILEFINDBUF2), &count) != 0) count = 0;
  465.         } while(count != 0);
  466.     }
  467.     (void) DosFindClose(hd);
  468.  
  469.     free(work);
  470. }
  471.  
  472.  
  473. /*
  474.  * Get current default drive
  475.  *
  476.  */
  477.  
  478. static void curdrv(CHAR *sp)
  479. {    int drive = _getdrive();
  480.  
  481.     *sp++ = (CHAR) (drive + 'a' - 1);
  482.     *sp++ = ':';
  483.     *sp = '\0';
  484. }
  485.  
  486.  
  487. /*
  488.  * Get space left on requested drive
  489.  *
  490.  */
  491.  
  492. static ULONG getleft(CHAR *pp, int *drv)
  493. {    ULONG cs;
  494.     FSALLOCATE fsall;
  495.     int drive;
  496.  
  497.     if(*(pp+1) == ':') {        /* Use specified drive if any */
  498.         drive = tolower(*pp) - 'a' + 1;
  499.     } else {
  500.         drive = _getdrive();
  501.     }
  502.     *drv = drive;
  503.  
  504.     (void) DosQFSInfo(drive, 1, (PBYTE) &fsall, sizeof(fsall));
  505.     cs = fsall.cSectorUnit * fsall.cbSector;    /* Bytes/cluster */
  506.  
  507.     return(cs * fsall.cUnitAvail);        /* # of unused clusters */
  508. }
  509.  
  510.  
  511. /*
  512.  * Return a file date in normalised form
  513.  *
  514.  */
  515.  
  516. static ULONG ndate(FDATE n)
  517. {    return(n.year*12L + n.month)*31L + n.day;
  518. }
  519.  
  520.  
  521. /*
  522.  * Return a file time in normalised form
  523.  *
  524.  */
  525.  
  526. static ULONG ntime(FTIME n)
  527. {    return((n.hours*60L + n.minutes)*30L + n.twosecs);
  528. }
  529.  
  530.  
  531. /*
  532.  * Compare two entries
  533.  *
  534.  */
  535.  
  536. static int comp(struct outbuf *a, struct outbuf *b)
  537. {    int y;
  538.  
  539.     if(tsrt) {
  540.         if(ndate(a->odate) != ndate(b->odate)) {
  541.                     /* If dates differ... */
  542.             y = (ndate(a->odate) < ndate(b->odate)) ? -1 : 1;
  543.                     /* ...that settles it... */
  544.         } else {
  545.             if(ntime(a->otime) == ntime(b->otime)) y = 0;
  546.             else y = (ntime(a->otime) < ntime(b->otime)) ? -1 : 1;
  547.                     /* ...else compare times */
  548.         }
  549.         return((rev) ? y : -y);
  550.     } else {
  551.         y = strcmpi(a->oname, b->oname);
  552.                     /* Name comparison */
  553.         return((rev) ? -y : y);
  554.     }
  555. }
  556.  
  557.  
  558. /*
  559.  * Print a list of names in 1 or 5 columns. Special action is needed for
  560.  * HPFS names, which may straddle columns.
  561.  *
  562.  */
  563.  
  564. static void shortlist(int k)
  565. {    int i;
  566.     int count = 0;
  567.     int width;
  568.     CHAR ch;
  569.     char *name;
  570.  
  571.     for(i = 0; i < k; i++) {
  572.         name = obuf[i].oname;
  573.         if(obuf[i].oattr & FILE_DIRECTORY)
  574.             (void) strcat(name, "\\");
  575.                     /* Mark directories */
  576.         if(fs == FS_FAT) {
  577.             (void) strlwr(name);
  578.             width = 15;
  579.         } else {
  580.             width = strlen(name);
  581.             if(width < 13) width = 13;
  582.             width = (width+16)/15*15;
  583.             if(width+count > SCRWID) {
  584.                 ch = endlin();
  585.                 fputc(ch, stdout);
  586.                 count = 0;
  587.             }
  588.         }
  589.  
  590.         /* Print the name and padding */
  591.  
  592.         fprintf(stdout, "%-*s", col1 ? strlen(name) : width, name);
  593.         count += width;
  594.         if(count >= SCRWID || col1) {
  595.             ch = endlin();
  596.             fputc(ch, stdout);
  597.             count = 0;
  598.         }
  599.     }
  600.     if(count) {            /* Finish incomplete line */
  601.         ch = endlin();
  602.         fputc(ch, stdout);
  603.     }
  604. }
  605.  
  606.  
  607. /*
  608.  * End a line and watch for screen overflow
  609.  *
  610.  */
  611.  
  612. static CHAR endlin()
  613. {    int c;
  614.  
  615.     if(tsc && ++lc >= SCRSIZ) {    /* Pause if output is to console screen */
  616.                     /* and we've shown a screenful */
  617.         fputs("\n--More--", stdout);
  618.         (void) fflush(stdout);
  619.         c = getch();
  620.         fputs("\b\b\b\b\b\b\b\b        \b\b\b\b\b\b\b", stdout);
  621.  
  622.         switch(c) {
  623.             case '\r':    /* <RETURN> - show 1 more line */
  624.                 lc = SCRSIZ - 1;
  625.                 break;
  626.  
  627.             case 'q':    /* Quit with "q" or "ctrl-C" */
  628.             case 'Q':
  629.             case '\003':
  630.                 exit(EXIT_FAILURE);
  631.  
  632.             default:    /* else show another screenful */
  633.                 lc = 0;
  634.                 break;
  635.         }
  636.         return('\b');
  637.     } else return('\n');
  638. }
  639.  
  640.  
  641. /*
  642.  * List everything about files
  643.  *
  644.  */
  645.  
  646. static void longlist(int k)        /* k is total number to list */
  647. {    int i;
  648.     int cdate;
  649.     CHAR ch;
  650.     char *mon;
  651.     struct llst l;
  652.  
  653.     cdate = gcdate();        /* Get current date (in months) */
  654.  
  655.     for(i = 0; i < k; i++) {
  656.         fill(i, &l);        /* Fill llst structure */
  657.         fprintf(stdout, "%s%9ld  %2d %s ", l.fattr, l.size, l.day,
  658.             mname(l.mnum));
  659.         if(cdate >= (l.yr * 12 +l.mnum) + 12) {
  660.             fprintf(stdout, " %4d  ", l.yr);
  661.                     /* Print year if too old */
  662.         } else {
  663.             fprintf(stdout, "%2d:%02d%c ", l.hh, l.mm, l.ap);
  664.                     /* else print time */
  665.         }
  666.         if(fs == FS_FAT) (void) strlwr(obuf[i].oname);
  667.         fprintf(stdout, obuf[i].oname);
  668.         ch = endlin();
  669.         fputc(ch, stdout);
  670.     }
  671. }
  672.  
  673.  
  674. /*
  675.  * Fill long list structure with file information
  676.  *
  677.  */
  678.  
  679. static void fill(int i, struct llst *ll)
  680. {    if(obuf[i].oattr & FILE_DIRECTORY) {
  681.         ll->size = eas ? obuf[i].easize : 0;
  682.     } else {
  683.         ll->size = eas   ? obuf[i].easize :
  684.                usage ? obuf[i].oasize :
  685.                    obuf[i].osize;
  686.     }
  687.  
  688.     (void) strcpy(ll->fattr, "------");
  689.     if(obuf[i].oattr & FILE_DIRECTORY) ll->fattr[0] = 'd';
  690.     if(obuf[i].easize != 0) ll->fattr[1] = 'e';
  691.     if(obuf[i].oattr & FILE_ARCHIVED) ll->fattr[2] = 'a';
  692.     if(obuf[i].oattr & FILE_SYSTEM) ll->fattr[3] = 's';
  693.     if(obuf[i].oattr & FILE_HIDDEN) ll->fattr[4] = 'h';
  694.     if(obuf[i].oattr & FILE_READONLY) ll->fattr[5] = 'r';
  695.  
  696.     ll->day = obuf[i].odate.day;
  697.     ll->mnum = obuf[i].odate.month;
  698.     ll->yr = obuf[i].odate.year + 1980;
  699.     ll->hh = obuf[i].otime.hours;
  700.     ll->mm = obuf[i].otime.minutes;
  701.     ll->ap = ll->hh >= 12 ? 'p' : 'a';
  702.     if(ll->hh > 12)    ll->hh -= 12;
  703.     if(ll->hh == 0)    ll->hh = 12;
  704. }
  705.  
  706.  
  707. /*
  708.  * Get current date (in months) for comparison
  709.  *
  710.  */
  711.  
  712. static int gcdate()
  713. {    DATETIME dt;
  714.  
  715.     (void) DosGetDateTime(&dt);
  716.  
  717.     return(dt.year*12 + dt.month);
  718. }
  719.  
  720.  
  721. /*
  722.  * Convert month number to month name
  723.  *
  724.  */
  725.  
  726. static char *mname(int n)
  727. {    struct tm t;
  728.     static char res[4];
  729.  
  730.     if(n <= 0 || n > 12) return("???");
  731.  
  732.     t.tm_mon = --n;
  733.     (void) strftime(res, 3, "%b", &t);
  734.  
  735.     return(res);
  736. }
  737.  
  738.  
  739. /*
  740.  * Function to determine the type of file system on the drive specified
  741.  * in 'path'.
  742.  *
  743.  * Returns FS_FAT or FS_HPFS; any error causes the result to default to
  744.  * FS_FAT.
  745.  *
  746.  */
  747.  
  748. static enum fs_t fstype(CHAR *path)
  749. {    USHORT res;
  750.     UCHAR fsqbuf[FSQBUFSIZE];
  751.     UCHAR *p;
  752.     USHORT fsqbuflen = FSQBUFSIZE;
  753.     UCHAR drive[3];
  754.  
  755.     if(path[1] != ':') {        /* No drive in path - use default */
  756.         curdrv(drive);
  757.     } else {
  758.         drive[0] = path[0];
  759.         drive[1] = path[1];
  760.         drive[2] = '\0';
  761.     }
  762.  
  763.     if(DosQFSAttach(drive, 0, FSAIL_QUERYNAME, fsqbuf, &fsqbuflen, 0L) != 0)
  764.         return(FS_FAT);
  765.  
  766.     /* Set 'p' to point to the file system name */
  767.  
  768.     p = fsqbuf + sizeof(USHORT);    /* Point past device type */
  769.     p += (USHORT) *p + 2*sizeof(USHORT) + 1;
  770.                     /* Point past drive name and FS name */
  771.                     /* length */
  772.  
  773.     if(strcmp(p, "HPFS") == 0) return(FS_HPFS);
  774.  
  775.     return(FS_FAT);
  776. }
  777.  
  778. /*
  779.  * Function to indicate if a given file descriptor relates to the screen
  780.  * or keyboard. This replaces the MSC 6.0 version, which just says if the
  781.  * file descriptor describes any device.
  782.  *
  783.  */
  784.  
  785. static BOOL my_isatty(int fd)
  786. {    USHORT rc;
  787.     USHORT HandType;        /* Handle type (returned) */
  788.     USHORT FlagWord;        /* Device driver attribute (returned) */
  789.  
  790.     rc = DosQHandType((HFILE) fd, &HandType, &FlagWord);
  791.     if(rc != 0) return(FALSE);    /* Error */
  792.  
  793.     if((HandType & 0xff) != 1) return(FALSE);
  794.                     /* Not character device */
  795.  
  796.     if((FlagWord & 0x03) != 0) return(TRUE);
  797.                     /* Standard input or output */
  798.     return(FALSE);
  799. }
  800.  
  801.  
  802. /*
  803.  * Function to output program usage information
  804.  *
  805.  */
  806.  
  807. static void putusage(void)
  808. {    char **p = (char **) helpinfo;
  809.     char *q;
  810.  
  811.     for(;;) {
  812.         q = *p++;
  813.         if(*q == '\0') break;
  814.  
  815.         fprintf(stderr, q, progname);
  816.         fputc('\n', stderr);
  817.     }
  818.     fprintf(stderr, "\nThis is version %d.%d\n", VERSION, EDIT);
  819. }
  820.  
  821. /*
  822.  * End of file: ls.c
  823.  *
  824.  */
  825.